home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / utility / wzun11sr.zip / FILE_IO.C < prev    next >
Text File  |  1992-04-18  |  25KB  |  849 lines

  1. /*---------------------------------------------------------------------------
  2.  
  3.   file_io.c
  4.  
  5.   This file contains routines for doing direct input/output, file-related
  6.   sorts of things.
  7.  
  8.   ---------------------------------------------------------------------------*/
  9.  
  10.  
  11. #include "unzip.h"
  12. #ifdef  MSWIN
  13. #include <windows.h>
  14. #include "wizunzip.h"
  15. #include "replace.h"
  16. #endif
  17.  
  18.  
  19. /************************************/
  20. /*  File_IO Local Prototypes, etc.  */
  21. /************************************/
  22.  
  23. static int WriteBuffer __((int fd, unsigned char *buf, int len));
  24. static int dos2unix __((unsigned char *buf, int len));
  25.  
  26. int CR_flag = 0;        /* when last char of buffer == CR (for dos2unix()) */
  27.  
  28.  
  29.  
  30.  
  31.  
  32. /*******************************/
  33. /*  Function open_input_file() */
  34. /*******************************/
  35.  
  36. int open_input_file()
  37. {                               /* return non-0 if open failed */
  38.     /*
  39.      *  open the zipfile for reading and in BINARY mode to prevent cr/lf
  40.      *  translation, which would corrupt the bitstreams
  41.      */
  42.  
  43. #ifndef UNIX
  44.     zipfd = open(zipfn, O_RDONLY | O_BINARY);
  45. #else
  46.     zipfd = open(zipfn, O_RDONLY);
  47. #endif
  48.     if (zipfd < 1) {
  49.         fprintf(stderr, "error:  can't open zipfile [ %s ]\n", zipfn);
  50.         return (1);
  51.     }
  52.     return 0;
  53. }
  54.  
  55.  
  56.  
  57.  
  58.  
  59. /************************/
  60. /*  Function readbuf()  */
  61. /************************/
  62.  
  63. int readbuf(buf, size)
  64. char *buf;
  65. register unsigned size;
  66. {                               /* return number of bytes read into buf */
  67.     register int count;
  68.     int n;
  69.  
  70.     n = size;
  71.     while (size) {
  72.         if (incnt == 0) {
  73.             if ((incnt = read(zipfd, inbuf, INBUFSIZ)) <= 0)
  74.                 return (n-size);
  75.             /* buffer ALWAYS starts on a block boundary:  */
  76.             cur_zipfile_bufstart += INBUFSIZ;
  77.             inptr = inbuf;
  78.         }
  79.         count = min(size, incnt);
  80.         memcpy(buf, inptr, count);
  81.         buf += count;
  82.         inptr += count;
  83.         incnt -= count;
  84.         size -= count;
  85.     }
  86.     return (n);
  87. }
  88.  
  89.  
  90.  
  91.  
  92.  
  93. /**********************************/
  94. /*  Function create_output_file() */
  95. /**********************************/
  96.  
  97. int create_output_file()
  98. {                               /* return non-0 if creat failed */
  99.     /*
  100.      * Create the output file with default permissions.
  101.      */
  102.     extern int do_all;
  103.     char answerbuf[10];
  104.     UWORD holder;
  105.       int already_exists;
  106.  
  107.  
  108.  
  109.     CR_flag = 0;                /* Hack to get CR at end of buffer working. */
  110.  
  111. #ifndef VMS  /* creates higher version number instead of overwriting (will
  112.               * have to modify for VMS-style names with specific version
  113.               * numbers:  check for failure on creat()??? */
  114.     /*
  115.      * check if the file exists, unless do_all
  116.      */
  117.       already_exists = open(filename, 0);
  118.       if (already_exists >= 0)
  119.               close(already_exists);          /* before you forget */
  120.     if (!do_all) {
  121.         if (already_exists >= 0) {     /* first close it, before you forget! */
  122.  
  123.             /* ask the user before blowing it away */
  124. #ifdef MSWIN
  125.         {
  126.         FARPROC lpProcReplace;
  127.         int ReplaceDlgRetVal;    /* replace dialog return value        */
  128.  
  129.             ShowCursor(FALSE);      /* turn off cursor      */
  130.             SetCursor(hSaveCursor); /* restore the cursor   */
  131.             lpProcReplace = MakeProcInstance(Replace, hInst);
  132.             ReplaceDlgRetVal = DialogBoxParam(hInst, "Replace", hMainWnd, 
  133.                                             lpProcReplace, (DWORD)(LPSTR)filename);
  134.             FreeProcInstance(lpProcReplace);
  135.             switch (ReplaceDlgRetVal) {
  136.             case IDM_REPLACE_YES:
  137.                 break;
  138.             case IDM_REPLACE_ALL:
  139.                 do_all = 1;
  140.                 break;
  141.             case IDM_REPLACE_NO:
  142.                 while (ReadByte(&holder));
  143.                 hSaveCursor = SetCursor(hHourGlass);
  144.                 ShowCursor(TRUE);       /* show it      */
  145.                 return 1;       /* it's done! */
  146.             }
  147.             hSaveCursor = SetCursor(hHourGlass);
  148.             ShowCursor(TRUE);       /* show it      */
  149.         }
  150. #else
  151.             fprintf(stderr, "replace %s, y-yes, n-no, a-all: ", filename);
  152. #ifdef AMIGA
  153.             fflush(stderr);
  154. #endif
  155.             fgets(answerbuf, 9, stdin);
  156.  
  157.             switch (answerbuf[0]) {
  158.             case 'y':
  159.             case 'Y':
  160.                 break;
  161.             case 'a':
  162.             case 'A':
  163.                 do_all = 1;
  164.                 break;
  165.             case 'n':
  166.             case 'N':
  167.             default:
  168.                 while (ReadByte(&holder));
  169.                 return 1;       /* it's done! */
  170.             }
  171. #endif
  172.         }
  173.     }
  174.  
  175. #if defined(UNIX) && !defined(AMIGA)
  176.     {
  177.       int mask;
  178.         if (already_exists >= 0 && unlink(filename) < 0)
  179.               fprintf(stderr, "Can't unlink %s\n", filename);         /* So we own it */
  180.       mask = umask(0);
  181.       outfd = creat(filename, 0777 & f_attr);                  /* Unix */
  182.       umask(mask);
  183.     }
  184. #else /* !UNIX || AMIGA */
  185.      /* Some Unix archives yield impossible f_attr's !!!
  186.         Also, creating a file read-only makes absolutely no sense here
  187.         because we immediately close it and then open it using open()
  188.         and O_RDWR which could not work then. */
  189.     outfd = creat(filename, (S_IWRITE | S_IREAD) /* & f_attr */); /* PCs */
  190. #endif /* ?(UNIX && !AMIGA) */
  191. #else /* VMS */
  192.     outfd = creat(filename, 0, "rfm=stmlf", "rat=cr");         /* VMS */
  193. #endif /* ?VMS */
  194.  
  195.     if (outfd < 1) {
  196.         fprintf(stderr, "Can't create output file:  %s\n", filename);
  197.         return 1;
  198.     }
  199.     /*
  200.      * close the newly created file and reopen it in BINARY mode to
  201.      * disable all CR/LF translations
  202.      */
  203. #ifndef UNIX
  204. #ifdef THINK_C
  205.     /*
  206.      * THINKC's stdio routines have the horrible habit of
  207.      * making any file you open look like generic files
  208.      * this code tells the OS that it's a text file
  209.      */
  210.     if (aflag) {
  211.         fileParam pb;
  212.         OSErr err;
  213.  
  214.         CtoPstr(filename);
  215.         pb.ioNamePtr = filename;
  216.         pb.ioVRefNum = 0;
  217.         pb.ioFVersNum = 0;
  218.         pb.ioFDirIndex = 0;
  219.         err = PBGetFInfo(&pb,0);
  220.         if (err == noErr) {
  221.           pb.ioFlFndrInfo.fdCreator = 0x3F3F3F3F;
  222.             pb.ioFlFndrInfo.fdType = 'TEXT';
  223.             err = PBSetFInfo(&pb, 0);
  224.         }
  225.         PtoCstr(filename);
  226.     }
  227. #endif                          /* THINK_C */
  228.     if (!aflag) {
  229.         close(outfd);
  230.         outfd = open(filename, O_RDWR | O_BINARY);
  231.     }
  232. #endif                          /* !UNIX */
  233.     if (outfd < 1) {
  234.         fprintf(stderr, "Can't open output: %s\n", filename);
  235.         return 1;
  236.     }
  237.     return 0;
  238. }
  239.  
  240.  
  241.  
  242.  
  243.  
  244. /*****************************/
  245. /*  Function FillBitBuffer() */
  246. /*****************************/
  247.  
  248. int FillBitBuffer(bits)
  249. register int bits;
  250. {
  251.     /*
  252.      * Get the bits that are left and read the next UWORD.  This
  253.      * function is only used by the READBIT macro (which is used
  254.      * by all of the uncompression routines).
  255.      */
  256.     register int result = bitbuf;
  257.     UWORD temp;
  258.     int sbits = bits_left;
  259.  
  260.  
  261.     bits -= bits_left;
  262.  
  263.     /* read next UWORD of input */
  264.     bits_left = ReadByte(&bitbuf);
  265.     bits_left += ReadByte(&temp);
  266.  
  267.     bitbuf |= (temp << 8);
  268.     if (bits_left == 0)
  269.         zipeof = 1;
  270.  
  271.     /* get the remaining bits */
  272.     result = result | (int) ((bitbuf & mask_bits[bits]) << sbits);
  273.     bitbuf >>= bits;
  274.     bits_left -= bits;
  275.     return result;
  276. }
  277.  
  278.  
  279.  
  280.  
  281.  
  282. /************************/
  283. /*  Function ReadByte() */
  284. /************************/
  285.  
  286. int ReadByte(x)
  287. UWORD *x;
  288. {
  289.     /*
  290.      * read a byte; return 8 if byte available, 0 if not
  291.      */
  292.  
  293.  
  294.     if (csize-- <= 0)
  295.         return 0;
  296.  
  297.     if (incnt == 0) {
  298.         if ((incnt = read(zipfd, inbuf, INBUFSIZ)) <= 0)
  299.             return 0;
  300.         /* buffer ALWAYS starts on a block boundary:  */
  301.         cur_zipfile_bufstart += INBUFSIZ;
  302.         inptr = inbuf;
  303.     }
  304.     *x = *inptr++;
  305.     --incnt;
  306.     return 8;
  307. }
  308.  
  309.  
  310.  
  311. #ifdef FLUSH_AND_WRITE
  312. /***************************/
  313. /*  Function FlushOutput() */
  314. /***************************/
  315.  
  316. int FlushOutput()
  317. {                               /* return PK-type error code */
  318.     /* flush contents of output buffer */
  319.     /*
  320.      * This combined version doesn't work, and I sure can't see why not...
  321.      * probably something stupid, but how much can you screw up in 6 lines???
  322.      * [optimization problem??]
  323.      */
  324.     int len;
  325.  
  326.  
  327.     if (outcnt) {
  328.         UpdateCRC(outbuf, outcnt);
  329.  
  330.         if (!tflag) {
  331.             if (aflag)
  332.                 len = dos2unix(outbuf, outcnt);
  333. #ifdef MSWIN
  334.             if (_lwrite(outfd, outout, len) != len) {
  335. #else
  336.             if (write(outfd, outout, len) != len) {
  337. #endif
  338.                 fprintf(stderr, "Fatal write error.\n");
  339.                 return (50);    /* 50:  disk full */
  340.             }
  341.         }
  342.         outpos += outcnt;
  343.         outcnt = 0;
  344.         outptr = outbuf;
  345.     }
  346.     return (0);                 /* 0:  no error */
  347. }
  348.  
  349. #else                           /* separate flush and write routines */
  350. /***************************/
  351. /*  Function FlushOutput() */
  352. /***************************/
  353.  
  354. int FlushOutput()
  355. {                               /* return PK-type error code */
  356.     /* flush contents of output buffer */
  357.     if (outcnt) {
  358.         UpdateCRC(outbuf, outcnt);
  359.  
  360.         if (!tflag && WriteBuffer(outfd, outbuf, outcnt))
  361.             return (50);        /* 50:  disk full */
  362.  
  363.         outpos += outcnt;
  364.         outcnt = 0;
  365.         outptr = outbuf;
  366.     }
  367.     return (0);                 /* 0:  no error */
  368. }
  369.  
  370. /***************************/
  371. /*  Function WriteBuffer() */
  372. /***************************/
  373.  
  374. static int WriteBuffer(fd, buf, len)    /* return 0 if successful, 1 if not */
  375. int fd;
  376. unsigned char *buf;
  377. int len;
  378. {
  379.     if (aflag)
  380.         len = dos2unix(buf, len);
  381. #ifdef MSWIN
  382.     if (cflag)    /* if writing to console vs. actual file, write to Msg Window */
  383.     {
  384.         WriteBufferToMsgWin(outout, len, FALSE);
  385.         return 0;
  386.     }
  387.     if (_lwrite(fd, outout, len) != len) {
  388. #else
  389.     if (write(fd, outout, len) != len) {
  390. #endif
  391. #ifdef DOS_OS2
  392.         if (!cflag) {           /* ^Z treated as EOF, removed with -c */
  393. #endif
  394.             fprintf(stderr, "Fatal write error.\n");
  395.             return (1);         /* FAILED */
  396. #ifdef DOS_OS2
  397.         }
  398. #endif
  399.     }
  400.     return (0);
  401. }
  402.  
  403. #endif
  404.  
  405.  
  406.  
  407.  
  408. /************************/
  409. /*  Function dos2unix() */
  410. /************************/
  411.  
  412. static int dos2unix(buf, len)
  413. unsigned char *buf;
  414. int len;
  415. {
  416.     int new_len;
  417.     int i;
  418. #ifdef MSWIN
  419.     unsigned char _far *walker;
  420. #else
  421.     unsigned char *walker;
  422. #endif
  423.  
  424.     new_len = len;
  425.     walker = outout;
  426. #ifdef MACOS
  427.     /*
  428.      * Mac wants to strip LFs instead CRs from CRLF pairs
  429.      */
  430.     if (CR_flag && *buf == LF) {
  431.         buf++;
  432.         new_len--;
  433.         len--;
  434.         CR_flag = buf[len] == CR;
  435.     }
  436.     else
  437.         CR_flag = buf[len - 1] == CR;
  438.     for (i = 0; i < len; i += 1) {
  439.         *walker++ = ascii_to_native(*buf);
  440.         if (*buf == LF) walker[-1] = CR;
  441.         if (*buf++ == CR && *buf == LF) {
  442.             new_len--;
  443.             buf++;
  444.             i++;
  445.         }
  446.     }
  447. #else
  448.     if (CR_flag && *buf != LF)
  449.         *walker++ = ascii_to_native(CR);
  450.     CR_flag = buf[len - 1] == CR;
  451.     for (i = 0; i < len; i += 1) {
  452.         *walker++ = ascii_to_native(*buf);
  453.         if (*buf++ == CR && *buf == LF) {
  454.             new_len--;
  455.             walker[-1] = ascii_to_native(*buf++);
  456.             i++;
  457.         }
  458.     }
  459.     /*
  460.      * If the last character is a CR, then "ignore it" for now...
  461.      */
  462.     if (walker[-1] == ascii_to_native(CR))
  463.         new_len--;
  464. #endif
  465.     return new_len;
  466. }
  467.  
  468.  
  469.  
  470.  
  471.  
  472. #ifdef DOS_OS2
  473.  
  474. /***************************************/
  475. /*  Function set_file_time_and_close() */
  476. /***************************************/
  477.  
  478. void set_file_time_and_close()
  479.  /*
  480.   * MS-DOS AND OS/2 VERSION (Mac, Unix/VMS versions are below)
  481.   *
  482.   * Set the output file date/time stamp according to information from the
  483.   * zipfile directory record for this member, then close the file.  This
  484.   * is optional and can be deleted if your compiler does not easily support
  485.   * setftime().
  486.   */
  487. {
  488. /*---------------------------------------------------------------------------
  489.     Allocate local variables needed by OS/2 and Turbo C.  [OK, OK, so it's
  490.     a bogus comment...but this routine was getting way too cluttered and
  491.     needed some visual separators.  Bleah.]
  492.   ---------------------------------------------------------------------------*/
  493.  
  494. #ifdef OS2              /* (assuming only MSC or MSC-compatible compilers
  495.                          * for this part) */
  496.  
  497.     union {
  498.         FDATE fd;               /* system file date record */
  499.         UWORD zdate;            /* date word */
  500.     } ud;
  501.  
  502.     union {
  503.         FTIME ft;               /* system file time record */
  504.         UWORD ztime;            /* time word */
  505.     } ut;
  506.  
  507.     FILESTATUS fs;
  508.  
  509. #else                           /* !OS2 */
  510. #ifdef __TURBOC__
  511.  
  512.     union {
  513.         struct ftime ft;        /* system file time record */
  514.         struct {
  515.             UWORD ztime;        /* date and time words */
  516.             UWORD zdate;        /* .. same format as in .ZIP file */
  517.         } zt;
  518.     } td;
  519.  
  520. #endif                          /* __TURBOC__ */
  521. #endif                          /* !OS2 */
  522.  
  523. /*---------------------------------------------------------------------------
  524.      Do not attempt to set the time stamp on standard output.
  525.   ---------------------------------------------------------------------------*/
  526.  
  527.     if (cflag) {
  528.         close(outfd);
  529.         return;
  530.     }
  531.  
  532. /*---------------------------------------------------------------------------
  533.     Copy and/or convert time and date variables, if necessary; then set the
  534.     file time/date.
  535.   ---------------------------------------------------------------------------*/
  536.  
  537. #ifdef OS2
  538.  
  539.     DosQFileInfo(outfd, 1, &fs, sizeof(fs));
  540.     ud.zdate = lrec.last_mod_file_date;
  541.     fs.fdateLastWrite = ud.fd;
  542.     ut.ztime = lrec.last_mod_file_time;
  543.     fs.ftimeLastWrite = ut.ft;
  544.     DosSetFileInfo(outfd, 1, (PBYTE) &fs, sizeof(fs));
  545.  
  546. #else                           /* !OS2 */
  547. #ifdef __TURBOC__
  548.  
  549.     td.zt.ztime = lrec.last_mod_file_time;
  550.     td.zt.zdate = lrec.last_mod_file_date;
  551.     setftime(outfd, &td.ft);
  552.  
  553. #else                           /* !__TURBOC__:  MSC MS-DOS */
  554.  
  555.     _dos_setftime(outfd, lrec.last_mod_file_date, lrec.last_mod_file_time);
  556.  
  557. #endif                          /* !__TURBOC__ */
  558. #endif                          /* !OS2 */
  559.  
  560. /*---------------------------------------------------------------------------
  561.     And finally we can close the file...at least everybody agrees on how to
  562.     do *this*.  I think...
  563.   ---------------------------------------------------------------------------*/
  564.  
  565.     close(outfd);
  566. }
  567.  
  568.  
  569.  
  570.  
  571.  
  572. #else                           /* !DOS_OS2 */
  573. #ifdef MACOS                    /* Mac first */
  574.  
  575. /***************************************/
  576. /*  Function set_file_time_and_close() */
  577. /***************************************/
  578.  
  579. void set_file_time_and_close()
  580.  /*
  581.   * MAC VERSION
  582.   *
  583.   * First close the output file, then set its date/time stamp according
  584.   * to information from the zipfile directory record for this file.  [So
  585.   * technically this should be called "close_file_and_set_time()", but
  586.   * this way we can use the same prototype for either case, without extra
  587.   * #ifdefs.  So there.]
  588.   */
  589. {
  590.     long m_time;
  591.     DateTimeRec dtr;
  592.     ParamBlockRec pbr;
  593.     OSErr err;
  594.  
  595.     if (outfd != 1)
  596.     {
  597.         close(outfd);
  598.  
  599.         /*
  600.          * Macintosh bases all file modification times on the number of seconds
  601.          * elapsed since Jan 1, 1904, 00:00:00.  Therefore, to maintain
  602.          * compatibility with MS-DOS archives, which date from Jan 1, 1980,
  603.          * with NO relation to GMT, the following conversions must be made:
  604.          *      the Year (yr) must be incremented by 1980;
  605.          *      and converted to seconds using the Mac routine Date2Secs(),
  606.          *      almost similar in complexity to the Unix version :-)
  607.          *                                     J. Lee
  608.          */
  609.  
  610.         dtr.year = (((lrec.last_mod_file_date >> 9) & 0x7f) + 1980); /* dissect date */
  611.         dtr.month = ((lrec.last_mod_file_date >> 5) & 0x0f);
  612.         dtr.day = (lrec.last_mod_file_date & 0x1f);
  613.  
  614.         dtr.hour = ((lrec.last_mod_file_time >> 11) & 0x1f);      /* dissect time */
  615.         dtr.minute = ((lrec.last_mod_file_time >> 5) & 0x3f);
  616.         dtr.second = ((lrec.last_mod_file_time & 0x1f) * 2);
  617.         Date2Secs(&dtr, &m_time);
  618.         CtoPstr(filename);
  619.         pbr.fileParam.ioNamePtr = filename;
  620.         pbr.fileParam.ioVRefNum = pbr.fileParam.ioFVersNum = pbr.fileParam.ioFDirIndex = 0;
  621.         err = PBGetFInfo(&pbr, 0L);
  622.         pbr.fileParam.ioFlMdDat = pbr.fileParam.ioFlCrDat = m_time;
  623.         if (err == noErr) {
  624.             err = PBSetFInfo(&pbr, 0L);
  625.         }
  626.         if (err != noErr) {
  627.             printf("Error, can't set the time for %s\n",filename);
  628.         }
  629.  
  630.         /* set read-only perms if needed */
  631.         if (err != noErr && f_attr != 0) {
  632.             err = SetFLock(filename, 0);
  633.         }
  634.         PtoCstr(filename);
  635.     }
  636. }
  637.  
  638.  
  639. /* #elif defined(AMIGA) */
  640. #else
  641. #ifdef AMIGA
  642. #include <libraries/dos.h>
  643. void set_file_time_and_close()
  644. {
  645. /* This routine is derived from the unix routine. In AmigaDos, the
  646.  * counting begins 01-Jan-1978
  647.  */
  648.     long m_time;
  649.     int yr, mo, dy, hh, mm, ss, leap, days = 0;
  650.     struct DateStamp myadate;
  651.     if (cflag)                  /* can't set time on stdout */
  652.       return;
  653.     close(outfd);
  654.     yr = (((lrec.last_mod_file_date >> 9) & 0x7f) + 2); /* dissect date */
  655.     mo = ((lrec.last_mod_file_date >> 5) & 0x0f);
  656.     dy = ((lrec.last_mod_file_date & 0x1f) - 1);
  657.     hh = ((lrec.last_mod_file_time >> 11) & 0x1f);      /* dissect time */
  658.     mm = ((lrec.last_mod_file_time >> 5) & 0x3f);
  659.     ss = ((lrec.last_mod_file_time & 0x1f) * 2);
  660.     /* leap = # of leap years from 1978 up to but not including
  661.        the current year */
  662.     leap = ((yr + 1977) / 4);   /* Leap year base factor */
  663.     /* How many days from 1978 to this year? */
  664.     days = (yr * 365) + (leap - 492);
  665.     switch (mo) {               /* calculate expired days this year */
  666.     case 12:
  667.       days += 30;
  668.     case 11:
  669.       days += 31;
  670.     case 10:
  671.       days += 30;
  672.     case 9:
  673.       days += 31;
  674.     case 8:
  675.       days += 31;
  676.     case 7:
  677.       days += 30;
  678.     case 6:
  679.       days += 31;
  680.     case 5:
  681.       days += 30;
  682.     case 4:
  683.       days += 31;
  684.     case 3:
  685.       days += 28;             /* account for leap years (2000 IS one) */
  686.       if (((yr + 1978) % 4 == 0) && (yr + 1978) != 2100)  /* OK thru 2199 */
  687.           ++days;
  688.     case 2:
  689.       days += 31;
  690.     }
  691.     myadate.ds_Days   =   days+dy-2;
  692.     myadate.ds_Minute =   hh*60+mm;
  693.     myadate.ds_Tick   =   ss*TICKS_PER_SECOND;
  694.     if (!(SetFileDate(filename, &myadate)))
  695.       fprintf(stderr, "Error, can't set the time for %s\n",filename);
  696. }
  697.  
  698. #else                           /* !MACOS... */
  699. #ifndef MTS                     /* && !MTS (can't do): only one left is UNIX */
  700.  
  701. /***************************************/
  702. /*  Function set_file_time_and_close() */
  703. /***************************************/
  704.  
  705. void set_file_time_and_close()
  706.  /*
  707.   * UNIX AND VMS VERSION (MS-DOS & OS/2, Mac versions are above)
  708.   *
  709.   * First close the output file, then set its date/time stamp according
  710.   * to information from the zipfile directory record for this file.  [So
  711.   * technically this should be called "close_file_and_set_time()", but
  712.   * this way we can use the same prototype for either case, without extra
  713.   * #ifdefs.  So there.]
  714.   */
  715. {
  716.     long m_time;
  717.     int yr, mo, dy, hh, mm, ss, leap, days = 0;
  718. #ifdef VMS
  719.     char timbuf[24];
  720.     static char *month[] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
  721.                             "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
  722.     struct VMStimbuf {
  723.       char *actime;             /* VMS revision date, ASCII format */
  724.       char *modtime;            /* VMS creation date, ASCII format */
  725.     } ascii_times;
  726. #else /* !VMS */
  727.     struct utimbuf {
  728.       time_t atime;             /* New access time */
  729.       time_t mtime;             /* New modification time */
  730.     } tp;
  731. #ifdef BSD
  732.     static struct timeb tbp;
  733. #else /* !BSD */
  734. #ifdef AMIGA
  735.     extern char *_TZ;
  736. #else /* !AMIGA */
  737.     extern long timezone;
  738. #endif /* ?AMIGA */
  739. #endif /* ?BSD */
  740. #endif /* ?VMS */
  741.  
  742.  
  743.     close(outfd);
  744.  
  745.     if (cflag)                  /* can't set time on stdout */
  746.         return;
  747.  
  748.     /*
  749.      * These date conversions look a little weird, so I'll explain.
  750.      * UNIX bases all file modification times on the number of seconds
  751.      * elapsed since Jan 1, 1970, 00:00:00 GMT.  Therefore, to maintain
  752.      * compatibility with MS-DOS archives, which date from Jan 1, 1980,
  753.      * with NO relation to GMT, the following conversions must be made:
  754.      *      the Year (yr) must be incremented by 10;
  755.      *      the Date (dy) must be decremented by 1;
  756.      *      and the whole mess must be adjusted by TWO factors:
  757.      *          relationship to GMT (ie.,Pacific Time adds 8 hrs.),
  758.      *          and whether or not it is Daylight Savings Time.
  759.      * Also, the usual conversions must take place to account for leap years,
  760.      * etc.
  761.      *                                     C. Seaman
  762.      */
  763.  
  764.     yr = ((lrec.last_mod_file_date >> 9) & 0x7f) + 10; /* dissect date */
  765.     mo = (lrec.last_mod_file_date >> 5) & 0x0f;
  766.     dy = (lrec.last_mod_file_date & 0x1f) - 1;
  767.  
  768.     hh = (lrec.last_mod_file_time >> 11) & 0x1f;      /* dissect time */
  769.     mm = (lrec.last_mod_file_time >> 5) & 0x3f;
  770.     ss = (lrec.last_mod_file_time & 0x1f) * 2;
  771.  
  772. #ifdef VMS
  773.     sprintf(timbuf, "%02d-%3s-%04d %02d:%02d:%02d.00", dy+1, month[mo-1],
  774.       yr+1970, hh, mm, ss);
  775.  
  776.     ascii_times.actime = timbuf;
  777.     ascii_times.modtime = timbuf;
  778.  
  779.     if ((mm = VMSmunch(filename, SET_TIMES, &ascii_times)) != RMS$_NMF)
  780.         fprintf(stderr, "error %d:  can't set the time for %s\n", mm, filename);
  781.  
  782. #else /* !VMS */
  783.     /* leap = # of leap years from 1970 up to but not including
  784.        the current year */
  785.  
  786.     leap = ((yr + 1969) / 4);   /* Leap year base factor */
  787.  
  788.     /* How many days from 1970 to this year? */
  789.     days = (yr * 365) + (leap - 492);
  790.  
  791.     switch (mo) {               /* calculate expired days this year */
  792.     case 12:
  793.         days += 30;
  794.     case 11:
  795.         days += 31;
  796.     case 10:
  797.         days += 30;
  798.     case 9:
  799.         days += 31;
  800.     case 8:
  801.         days += 31;
  802.     case 7:
  803.         days += 30;
  804.     case 6:
  805.         days += 31;
  806.     case 5:
  807.         days += 30;
  808.     case 4:
  809.         days += 31;
  810.     case 3:
  811.         days += 28;             /* account for leap years (2000 IS one) */
  812.         if (((yr + 1970) % 4 == 0) && (yr + 1970) != 2100)  /* OK thru 2199 */
  813.             ++days;
  814.     case 2:
  815.         days += 31;
  816.     }
  817.  
  818.     /* convert date & time to seconds relative to 00:00:00, 01/01/1970 */
  819.     m_time = ((days + dy) * 86400) + (hh * 3600) + (mm * 60) + ss;
  820.  
  821. #ifdef BSD
  822.    ftime(&tbp);
  823.    m_time += tbp.timezone * 60L;
  824. #else /* !BSD */
  825. #ifdef AMIGA
  826.     _TZ = getenv("TZ");
  827. #endif
  828.     tzset();                            /* Set `timezone'. */
  829.     m_time += timezone;                 /* account for timezone differences */
  830. #endif /* ?BSD */
  831.  
  832.     if (localtime(&m_time)->tm_isdst)
  833.         m_time -= 60L * 60L;            /* Adjust for daylight savings time */
  834.  
  835.     /* set the time stamp on the file */
  836.     tp.mtime = m_time;                  /* Set modification time */
  837.     tp.atime = m_time;                  /* Set access time */
  838.  
  839.     if (utime(filename, &tp))
  840.         fprintf(stderr, "error:  can't set the time for %s\n",filename);
  841. #endif /* ?VMS */
  842. }
  843.  
  844. #endif                          /* ?MTS */
  845. #endif                          /* ?MACOS */
  846. #endif                          /* ?AMIGA */
  847. #endif                          /* ?DOS_OS2 */
  848. 
  849.